use std::sync::Arc;

use crate::classfile;

use super::{ConstantPool, class::Class, method::Method, method_lookup};

// 方法符号引用
#[derive(Clone)]
pub struct MethodRef{
    cp: Arc<ConstantPool>,
    class_name: String, // 类的完全限定名
    class: Option<Arc<Class>>, // 缓存解析后的类结构体
    // cp_symref ↑
    name: String,
    descriptor: String,
    // cp_memberref ↑
    method: Option<Arc<Method>>
}


// cp_symref
impl MethodRef {
    // 方法符号引用解析
    pub fn resolved_class(&mut self) -> Arc<Class> {
        if self.class.is_none() {
            self.resolve_class_ref();
        }
        self.class.as_ref().unwrap().clone()
    }

    // 解析class引用
    fn resolve_class_ref(&mut self) {
        let d = self.cp.get_class();
        let loader = d.get_class_loader().unwrap();
        // TODO class_name 用的clone，后续调整标记
        let c = loader.lock().unwrap().load_class(self.class_name.clone());
        if !c.is_accessible_to(&d) {
            panic!("java.lang.IllegalAccessError");
        }
        self.class = Some(c);
    }
}

// cp_memberref
impl MethodRef {
    // 从class文件内存储的字段或方法常量中提取数据
    pub fn copy_member_ref_info(&mut self, ref_info: &classfile::ConstantMethodrefInfo) {
        self.class_name = ref_info.class_name();
        let (name, deciroptor) = ref_info.name_and_descriptor();
        self.name = name;
        self.descriptor = deciroptor;
        // 231214 不清楚为何会出现([Lint;[Lint;)I这种描述符，若出现直接替换。
        if self.descriptor.contains("Lint;") {
            self.descriptor = self.descriptor.replace("Lint;", "I")
        }
    }

    pub fn get_name(&self) -> &str {
        &self.name
    }

    pub fn get_descriptor(&self) -> &str {
        &self.descriptor
    }
}


impl MethodRef {
    pub fn new_method_ref(cp: Arc<ConstantPool>, ref_info: &classfile::ConstantMethodrefInfo) -> MethodRef {
        let mut method_ref = MethodRef {
            cp,
            class_name: String::default(), 
            class: None, 
            name: String::default(), 
            descriptor: String::default(), 
            method: None 
        };
        method_ref.copy_member_ref_info(ref_info);
        method_ref
    }

    // 方法符号引用解析
    pub fn resolved_method(&mut self) -> Arc<Method> {
        if self.method.is_none() {
            self.resolved_method_ref()
        }
        self.method.clone().unwrap()
    }

    // 解析方法引用
    fn resolved_method_ref(&mut self) {
        let c = self.resolved_class();
        let d = self.cp.get_class();
        if c.is_interface() {
            panic!("java.lang.IncompatibleClassChangeError")
        }
        match Self::lookup_method(c.clone(), &self.name, &self.descriptor) {
            // Some(method) if !method.is_accessible_to(d) => panic!("java.lang.IllegalAccessError"), // 无权访问
            Some(method) if !method.is_accessible_to(d.clone()) => {
                dbg!(c.get_name());
                dbg!(d.get_name());
                panic!("java.lang.IllegalAccessError");
            }, // 无权访问

            Some(method) => self.method = Some(method), // 设置method
            None => {
                // c.get_name() = "Lambda3Test"
                // self.name.clone() = "lambda$main$0"
                // self.descriptor.clone() = "([Lint;[Lint;)I"
                // [Lint; ????????????????????????? 这什么东西。
                dbg!(c.get_name());
                dbg!(self.name.clone());
                dbg!(self.descriptor.clone());
                panic!("java.lang.NoSuchFieldError")
            }
        }
    }

    // 查找方法
    fn lookup_method(c: Arc<Class>, name: &str, descriptor: &str) -> Option<Arc<Method>> {
        // 继承层次中找
        if let Some(method) = method_lookup::lookup_method_in_class(c.clone(), name, descriptor) {
            return Some(method);
        }
        // 实现接口中查找
        method_lookup::lookup_method_in_interfaces(c.get_interfaces(), name, descriptor)
    }
}
